using System;
using System.IO;
using System.Linq;
using ExcelLibrary.SpreadSheet;
using ResxHelper.Object;

namespace ResxHelper.Logic.Formatters
{
    public class ResourceFileExcelFormatter : IResourceFileFormatter
    {

        public ResourceFile InputFile { get; private set; }

        public ResourceFileExcelFormatter(ResourceFile file)
        {
            InputFile = file;
        }

        public string Run()
        {
            var workbook = new Workbook();
            var sheet = new Worksheet("Resources");
            var rowCount = InputFile.Entries.Count;
            var entries = InputFile.Entries.Values.ToArray();

            // populate the sheet
            for (var i = 0; i < rowCount; i++)
            {
                sheet.Cells[i, 0] = new Cell(entries[i].Key);
                sheet.Cells[i, 1] = new Cell(entries[i].Value);
                sheet.Cells[i, 2] = new Cell(entries[i].Comment);
            }

            workbook.Worksheets.Add(sheet);

            // export as base64 stream just to satisfy IResourceFileFormatter
            using (var stream = new MemoryStream())
            {
                workbook.SaveToStream(stream);
                
                stream.Position = 0;
                var xlsByte = ReadStream(stream);
                var base64 = Convert.ToBase64String(xlsByte);
                return base64;
            }
        }

        private static byte[] ReadStream(Stream stream)
        {
            long originalPosition = 0;

            if (stream.CanSeek)
            {
                originalPosition = stream.Position;
                stream.Position = 0;
            }

            try
            {
                var readBuffer = new byte[4096];

                var totalBytesRead = 0;
                int bytesRead;

                while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
                {
                    totalBytesRead += bytesRead;

                    if (totalBytesRead != readBuffer.Length) continue;

                    var nextByte = stream.ReadByte();
                    if (nextByte == -1) continue;

                    var temp = new byte[readBuffer.Length * 2];
                    Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                    Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                    readBuffer = temp;
                    totalBytesRead++;
                }

                var buffer = readBuffer;
                if (readBuffer.Length != totalBytesRead)
                {
                    buffer = new byte[totalBytesRead];
                    Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
                }
                return buffer;
            }
            finally
            {
                if (stream.CanSeek)
                {
                    stream.Position = originalPosition;
                }
            }
        }

    }
}
